/**
 * @(#) Sensor.java
 */

package pcsr.hwVirtualization;

import java.util.*;

import pcsr.exceptions.PCSRSensorRuntimeException;

/**
 * Represents a virtualized sensor, managed by PCSR.
 * @author Paulo Fagundes
 *
 */
public class Sensor implements ISensorActions, ISensorObservable
{
	private IRobotDriver robot;
	
	private String sensorID;
	
	private List<ISensorObserver> sensorObservers;

	private SensorMode sensorOperationMode;
	
	private SensorValue sensorValue;
	
	/**
	 * Gets the current operating mode of the sensor.
	 * @return The sensorOperationMode
	 */
	public SensorMode GetOperationMode( ) {
		try
		{
			return sensorOperationMode;
		}
		catch (RuntimeException re) {
			throw new PCSRSensorRuntimeException(re);
		}
	}
	
	/**
	 * Gets the sensor identifier.
	 * @return The sensorID
	 */
	public String GetSensorID( ) {
		try
		{
			return sensorID;
		}
		catch (RuntimeException re) {
			throw new PCSRSensorRuntimeException(re);
		}
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Sensor GetSensorStatus( ) {
		try
		{
			return (Sensor) this.clone();
		} catch (Exception e) {
			throw new PCSRSensorRuntimeException(e);
		}
	}

	/**
	 * Gets the sensor value.
	 * @return The sensorValue
	 */
	public SensorValue GetSensorValue( ) {
		try
		{
			return sensorValue;
		}
		catch (RuntimeException re) {
			throw new PCSRSensorRuntimeException(re);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void ObserveSensor( ISensorObserver observer ) {
		try
		{
			sensorObservers.add(observer);
		} catch (Exception e) {
			throw new PCSRSensorRuntimeException(e);
		}
	}
	
	/**
	 * Sets a new operating mode for the sensor.
	 * <p><strong>Remarks:</strong> This method is for driver use only.</p>
	 * @param sensorMode The sensorMode to set
	 */
	public void SetMode( SensorMode sensorMode ) {
		try
		{
			this.sensorOperationMode = sensorMode;
			NotifyObservers();
		}
		catch (RuntimeException re) {
			throw new PCSRSensorRuntimeException(re);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void SetSensorMode( SensorMode sensorMode ) {
		try
		{
			this.sensorOperationMode = sensorMode;
			robot.SetSensorStatusToDriver(this);
		} catch (Exception e) {
			throw new PCSRSensorRuntimeException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void SetSensorValue( SensorValue sensorValue ) {
		try
		{
			this.sensorValue = sensorValue;
			robot.SetSensorStatusToDriver(this);
		} catch (Exception e) {
			throw new PCSRSensorRuntimeException(e);
		}
	}

	/**
	 * Sets a new value for the sensor.
	 * <p><strong>Remarks:</strong> This method is for driver use only.</p>
	 * @param sensorValue The sensorValue to set
	 */
	public void SetValue( SensorValue sensorValue ) {
		try
		{
			this.sensorValue = sensorValue;
			NotifyObservers();
		}
		catch (RuntimeException re) {
			throw new PCSRSensorRuntimeException(re);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void UnObserveSensor( ISensorObserver observer ) {
		try
		{
			sensorObservers.remove(observer);
		} catch (Exception e) {
			throw new PCSRSensorRuntimeException(e);
		}
	}

	/**
	 * Notify all subscribers that the sensor has changed.
	 */
	private void NotifyObservers()
	{
		for(ISensorObserver is : sensorObservers)
		{
			is.SensorChanged(this);
		}
	}

	/**
	 * Sets the {@code IRobotDriver} that connects to driver.
	 * @param robot The robot to set
	 */
	void setRobotDriver(IRobotDriver robot) {
		this.robot = robot;
	}
	
	{
		sensorObservers = new LinkedList<ISensorObserver>();
	}

	/**
	 * Sensor constructor.
	 * @param ID The sensor identifier
	 */
	public Sensor(String ID)
	{
		sensorID = ID;
	}
}
